package cn.zyl.demo.qle.tools;

import cn.zyl.demo.qle.express.SpringExpressContext;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Map;

/** SpringExpressTool工具类说明:
 * <p>参考：<a href="https://blog.csdn.net/express_wind/article/details/84230455">扩展QLExpress来管理spring的bean</a>,进行管理</p>
 * @author z.y.l
 * @date 2020-08-28
 * @version v1.0
 */
@Component
public class SpringExpressTool implements ApplicationContextAware {
    /** 语法分析和计算的入口 */
    private static final ExpressRunner RUNNER;
    /** 是否运行的变量 */
    private static boolean isInitialRunner = false;
    /** spring 上下文 */
    private static ApplicationContext context;
    static {
        RUNNER = new ExpressRunner();
    }
    /** 在此处把一些中文符号替换成英文符号 */
    private static String initStatement(String str){
        return str.replace("（", "(").replace("）", ")").replace("；", ";")
                .replace("，", ",").replace("“", "\"").replace("”", "\"");
    }
    /** 初始化ExpressRunner */
    private static void initRunner(){
        if(isInitialRunner){return;}
        synchronized (SpringExpressTool.RUNNER){
            if(isInitialRunner){return;}
            try {
                //在此可以加入预定义函数
                String expressService = "expressService";
                //将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数
                addFunSerMethod("客户信息",expressService, "getById",new Class[]{Long.class},"$1的客户信息获取失败");
                addFunSerMethod("客户新增",expressService, "saveOne",new Class[]{Long.class,String.class,Integer.class},"新增客户信息失败：$1,$2,$3");
                addFunSerMethod("客户列表",expressService, "queryList",new Class[]{String.class},"$1相关的客户列表获取失败");
            } catch (Exception e) {
                throw new RuntimeException("初始化失败表达式",e);
            }
            isInitialRunner = true;
        }
    }
    /** 将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数 */
    private static void addFunSerMethod(String expressName,String beanName,String methodName,Class<?>[] classes,String errorInfo) throws Exception {
        SpringExpressTool.RUNNER.addFunctionOfServiceMethod(expressName, context.getBean(beanName), methodName, classes,errorInfo);
    }
    /**
     * 执行QlExpress的语法
     * @param statement QlExpress的执行语句
     * @param qleContext 上下文
     * @return 执行结果
     * @throws Exception 异常
     */
    public static Object execute(String statement, Map<String,Object> qleContext)throws Exception{
        initRunner();
        IExpressContext<String,Object> expressContext = new SpringExpressContext<>(qleContext,context);
        statement = initStatement(statement);
        return RUNNER.execute(statement, expressContext, null, true, true);
    }
    /**
     * 设置该对象在其中运行的ApplicationContext。通常，此调用将用于初始化该对象。
     * @param applicationContext 该对象要使用的ApplicationContext对象
     * @throws BeansException              如果由应用程序上下文方法抛出
     * @see BeanInitializationException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
}